package com.tomtop.core.web.config;

import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ThreadFactory;

import org.apache.http.Header;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.MimeTypeUtils;

@Configuration
@ConditionalOnMissingBean(ClientHttpRequestFactory.class)
@ConditionalOnClass(PoolingHttpClientConnectionManager.class)
public class HttpComponentsConfig {

    final static Logger LOGGER = LoggerFactory.getLogger(HttpComponentsConfig.class);
    
	@ConditionalOnMissingBean( ThreadFactory.class)
	@Bean ThreadFactory threadFactory(){ return new ThreadPoolTaskExecutor(); }
	
	@ConditionalOnMissingBean
	@Bean RequestConfig.Builder requestConfig() { 
		return RequestConfig.custom()
				.setConnectionRequestTimeout(8000)
				.setConnectTimeout(300000)
				.setSocketTimeout(300000)
				.setMaxRedirects(1000)
				.setRedirectsEnabled(true)
				;
	}

	@ConditionalOnMissingBean
	@Bean SocketConfig.Builder socketConfig() { 
		return SocketConfig.custom()
				.setSoTimeout(60000)
				.setSoKeepAlive(true)
				;
	}

	@ConditionalOnMissingBean
	@Bean HttpRequestRetryHandler requestRetryHandler(){
		return new DefaultHttpRequestRetryHandler(3, true);
	}
	
	@ConditionalOnMissingBean
	@Bean Collection<? extends Header> defaultHeaders() { return Collections.singletonList(new BasicHeader("Content-Type", MimeTypeUtils.APPLICATION_JSON_VALUE )); }

	@ConditionalOnMissingBean
	@Bean String userAgent(@Value("${spring.application.name:Other}") String app) { return "laolei HttpClient( "+app+")"; }
	
	@ConditionalOnMissingBean
	@Bean RegistryBuilder<ConnectionSocketFactory> registryConnectionSocketFactory() {
		return RegistryBuilder.<ConnectionSocketFactory>create()
		.register("http", PlainConnectionSocketFactory.getSocketFactory())
		.register("https", SSLConnectionSocketFactory.getSystemSocketFactory())
		; 
	}
	
	@Bean(destroyMethod="close") PoolingHttpClientConnectionManager syncConnectionPoolManager(RegistryBuilder<ConnectionSocketFactory> registryBuilder,SocketConfig.Builder socketConfig){
		PoolingHttpClientConnectionManager poolConnManager = new PoolingHttpClientConnectionManager(registryBuilder.build());
		poolConnManager.setDefaultSocketConfig(socketConfig.build());
		poolConnManager.setMaxTotal(150);
		poolConnManager.setDefaultMaxPerRoute(10);
		poolConnManager.setValidateAfterInactivity(1900);
		return poolConnManager;
	}
	
	@Scheduled(fixedDelay=6*60*1000,initialDelay=1000) void showHttpConnectionPoolState(){
		LOGGER.debug("当前http连接池状态 {}",syncConnectionPoolManager(null, null).getTotalStats());
	}
	
	@Bean HttpClientBuilder httpClient(HttpRequestRetryHandler requestRetryHandler,RequestConfig.Builder requestConfig,HttpClientConnectionManager syncConnectionPoolManager,Collection<? extends Header> defaultHeaders,String userAgent){
		HttpClientBuilder clientBuilder = HttpClients.custom()
				.setConnectionManager(syncConnectionPoolManager)
				.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
				.setConnectionManagerShared(true)
				.setDefaultRequestConfig(requestConfig.build())
				.setDefaultHeaders(defaultHeaders)
				.setRetryHandler(requestRetryHandler)
				.setUserAgent(userAgent)
				;
		return clientBuilder;
	}

	@Bean ClientHttpRequestFactory clientHttpRequestFactory(HttpClientBuilder httpClient) {
		return new HttpComponentsClientHttpRequestFactory(httpClient.build());
	}
}
